<?php

namespace App\Services\spider;

use App\Model\CommonSpiderItem;
use App\Services\UtilService;
use SimpleHtmlDom\simple_html_dom;
use TheSeer\Tokenizer\Exception;

class CommonSpider
{


    private string $taskNo;
    private TypeValidator $typeValidator;
    private IUrParser $urlParser;
    //
    private int $webCount;//抓取网页数
    private int $targetCount;//抓取到的个数
    private IDataRepo $repo;
    protected int $index=1;

    /**
     * @param array $startUrls
     * @param string $taskNo
     * @param TypeValidator $typeValidator
     * @param IUrParser $urlParser
     */
    public function __construct(array $startUrls, string $taskNo, TypeValidator $typeValidator, IUrParser $urlParser)
    {
        $this->taskNo = $taskNo;
        $this->typeValidator = $typeValidator;
        $this->urlParser = $urlParser;
        $this->repo = $urlParser->getRepo();
        $this->addItems($startUrls);
    }
    public function getTaskNo(): string
    {
        return $this->taskNo;
    }

    public function start()
    {
        $this->loop();
    }


    public function loopError()
    {
        while (true) {
            $list = $this->repo->errorItems($this->taskNo);
            foreach ($list as $item) {
                $this->onHandleUrl($item->url, true);
            }
            if ($list->count() < 1) {
                break;
            }
        }
    }

    private function onHandleSelf($type, $url, $content)
    {
        //处理目标网页
        if ($type) {
            $parseResult = $this->typeValidator->parseHtml($url, $content);
            if ($parseResult->success) {
                $this->repo->updateItem($this->taskNo, $url, [
                    'type' => $type,
                    'parse_status' => CommonSpiderItem::parse_status_success,
                    'data' => $parseResult->data
                ]);
                UtilService::getInstance()->print("parse url=$url;success---------");
            } else {
                if ($parseResult->ignore) {
                    $this->repo->updateItem($this->taskNo, $url, [
                        'type' => $type,
                        'parse_status' => CommonSpiderItem::parse_status_ignore,
                    ]);
                    UtilService::getInstance()->print("parse url=$url;ignore <<<<<<<");
                } else {
                    UtilService::getInstance()->print("parse html error,url=$url,error:" . $parseResult->error);
                    $this->repo->updateItem($this->taskNo, $url, [
                        'type' => $type,
                        'parse_status' => CommonSpiderItem::parse_status_error,
                    ]);
                }
            }
        }
    }

    private function parseATag($url, $content)
    {
        //解析网页中所有的a标签，并添加
        $html = new simple_html_dom();
        $html->load($content);
        $nodes = $html->find("a");
        $hrefUrls = [];
        foreach ($nodes as $node) {
            $hrefUrl = $this->urlParser->filterATagHref($node->href, $url);
            if ($hrefUrl) {
                $hrefUrls[] = $hrefUrl;
            }
        }
        $this->addItems($hrefUrls);
    }

    private function onHandleUrl(?string $url, $force = false)
    {
        if (empty($url)) {
            return;
        }
        UtilService::getInstance()->print("index={$this->index}");
        $this->index++;
        // 只处理我们需要的链接
        if ($this->urlParser->isNeedUrl($url)) {
            UtilService::getInstance()->print("common onHandle url = $url");
            //过滤掉已处理的链接
            $handledItem = $this->repo->handledItem($this->taskNo, $url);
            UtilService::getInstance()->print("common onHandle url 1.1");
            $type = $this->typeValidator->isTarget($url);
            $isTarget = $type ? 1 : 0;
            if ($force || !$handledItem) {
                UtilService::getInstance()->print("common onHandle url 1.2");
                $urlParserResult = $this->urlParser->parse($url, $this->taskNo);
                UtilService::getInstance()->print("common onHandle url 2");
                if ($urlParserResult->success) {
                    $content = $urlParserResult->content;
                    //更新item状态

                    if (!$handledItem) {
                        $success = $this->repo->updateItem($this->taskNo, $url, [
                            "html_code" => CommonSpiderItem::html_code_success,
//                            "html" => $content,
                            'is_target' => $isTarget
                        ]);
                        if (!$success) {
                            return;
                        }
                    }
                    UtilService::getInstance()->print("common onHandle url 3");
                    $this->onHandleSelf($type, $url, $content);
                    if (!$force && $isTarget) {
                        //target count ++
                    }
                    if (!$handledItem||$force) {
                        UtilService::getInstance()->print("common onHandle ur 4 parseATag url=$url");
                        $this->parseATag($url, $content);

                    }
                } else {
                    UtilService::getInstance()->print("common onHandle url 5");
                    $this->repo->updateItem($this->taskNo, $url, [
                        "html_code" => $urlParserResult->html_code,
                        'is_target' => $isTarget
                    ]);
                }
            }
        }
        UtilService::getInstance()->print("-------------common onHandle url end ----------------------------");

    }

    /**
     * @return mixed
     */
    private function loop()
    {
        while (true) {
            try{
                $list = $this->repo->unHandleItems($this->taskNo);

                foreach ($list as $item) {

                    $this->onHandleUrl($item->url);
                }
                if ($list->count() < 1) {
                    break;
                }
            }catch (\Throwable $e){
                UtilService::getInstance()->print("loop exception:".$e->getMessage());
            }

        }
        UtilService::getInstance()->print("所有网页已经处理完成");
        return;
    }


    public function handleUrl($url)
    {
        $this->addItems([$url]);
        $this->onHandleUrl($url, true);
    }

    public function addItems(array $urls)
    {
        $urls = $this->repo->filterExists($this->taskNo, $urls);
        if (empty($urls)) {
            return;
        }
        UtilService::getInstance()->transaction(function () use ($urls) {
            foreach ($urls as $url) {
                $s = $this->urlParser->isNeedUrl($url);
                if ($s) {
                    CommonSpiderItem::of($url, $this->taskNo, !!$this->typeValidator->isTarget($url))->save();
                }
            }
        });
    }

    public function autoAddQgyydqItemByName(){


    }




}